package handler

import (
	"context"
	"trade_rpc/global"
	"trade_rpc/model"
	pb "trade_rpc/proto"
	"trade_rpc/util"

	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type TradeServer struct {
	pb.UnimplementedTradeRecordServer
}

func (s *TradeServer) CreateTradeRecord(ctx context.Context, req *pb.CreateTradeRecordRequest) (*pb.CreateTradeRecordResponse, error) {

	// TODO: 考虑双写一致性问题

	// 生成存证哈希
	hashText, err := util.GenerateTradeRecordEnvidence(&util.TradeData{
		TradeID:             req.TradeId,
		TradeSn:             req.TradeSn,
		UserID:              req.UserId,
		SnapTime:            req.SnapTime,
		LicensePlateNumber:  req.LicensePlateNumber,
		LicensePlateNumber2: req.LicensePlateNumber2,
		RecordIDs:           req.RecordIds,
		RecordProvinceCodes: req.RecordProvinceCodes,
		Prices:              req.Prices,
		TotalPrice:          req.TotalPrice,
	})
	if err != nil {
		zap.L().Error("生成存证哈希错误", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "generate trade record envidence failed")
	}

	// 避免哈希碰撞，这里的存证哈希，存储为ProvinceCode:TradeID:HashText
	hashText = req.ProvinceCode + ":" + req.TradeId + ":" + hashText

	// 1. 写入到对应的区块链系统中
	tx, receipt, err := global.TradeManager.CreateTradeProve(global.Client.GetTransactOpts(), req.UserId, req.TradeId, req.SnapTime, hashText)

	if err != nil {
		zap.L().Error("数据上链失败",
			zap.Error(err),
			zap.Any("record",
				req),
		)
		return nil, status.Errorf(codes.Internal, "create trade record prove failed with contract")
	}

	zap.L().Debug("交易的状态", zap.Int("status", receipt.Status))

	record := model.TradeRecord{
		TradeID:             req.TradeId,
		TradeSn:             req.TradeSn,
		UserID:              req.UserId,
		SnapTime:            req.SnapTime,
		LicensePlateNumber:  req.LicensePlateNumber,
		LicensePlateNumber2: req.LicensePlateNumber2,
		RecordIDs:           req.RecordIds,
		RecordProvinceCodes: req.RecordProvinceCodes,
		Prices:              req.Prices,
		TotalPrice:          req.TotalPrice,
		BlockChainHashCode:  tx.Hash().Hex(),
		RecordHashCode:      hashText,
		Status:              0,
		TradeStatus:         0,
	}
	result := global.DB.Save(&record)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "create trade record failed with database")
	}
	return &pb.CreateTradeRecordResponse{
		Id:       int32(record.ID),
		HashText: hashText,
		TxHash:   tx.Hash().Hex(),
	}, nil
}

func (s *TradeServer) GetTradeRecord(ctx context.Context, req *pb.GetTradeRecordRequest) (*pb.GetTradeRecordResponse, error) {

	record := model.TradeRecord{}
	result := global.DB.Model(&model.TradeRecord{}).Where("record_hash_code = ?", req.HashText).First(&record)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "get trade record failed")
	}
	return &pb.GetTradeRecordResponse{
		TradeId:             record.TradeID,
		TradeSn:             record.TradeSn,
		UserId:              record.UserID,
		SnapTime:            record.SnapTime,
		LicensePlateNumber:  record.LicensePlateNumber,
		LicensePlateNumber2: record.LicensePlateNumber2,
		RecordIds:           record.RecordIDs,
		RecordProvinceCodes: record.RecordProvinceCodes,
		Prices:              record.Prices,
		TotalPrice:          record.TotalPrice,
		BlockChainHashCode:  record.BlockChainHashCode,
		RecordHashCode:      record.RecordHashCode,
	}, nil
}
